package com.yupi.yoj.utils;

import javax.annotation.Resource;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import cn.hutool.json.JSONUtil;
import com.yupi.yoj.common.ErrorCode;
import com.yupi.yoj.config.jwt.JwtProperties;
import com.yupi.yoj.exception.BusinessException;
import com.yupi.yoj.exception.ThrowUtils;
import com.yupi.yoj.model.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClaims;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JWTUtil {
    @Resource
    JwtProperties jwtProperties;


    /**
     * 由字符串生成加密key
     * @return
     */
    private SecretKey generalKey() {
        // 本地的密码解码
        byte[] encodedKey = Base64.decodeBase64(jwtProperties.getSecret());
        // 根据给定的字节数组使用AES加密算法构造一个密钥
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }


    /**
     * 创建jwt
     * @param subject
     * @return
     * @throws Exception
     */
    public String createJWT(String subject) throws RuntimeException {

        // 生成JWT的时间
        long nowTime = System.currentTimeMillis();
        Date nowDate = new Date(nowTime);
        // 生成签名的时候使用的秘钥secret，切记这个秘钥不能外露，
        // 是你服务端的私钥，在任何场景都不应该流露出去，
        // 一旦客户端得知这个secret，那就意味着客户端是可以自我签发jwt的
        SecretKey key = generalKey();

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine se = manager.getEngineByName("js");
        int expireTime = 0;
        try {
            expireTime =(int) se.eval(jwtProperties.getPayload().getRegisterdClaims().getExp());
        } catch (ScriptException e) {
            e.printStackTrace();
        }

        // 为payload添加各种标准声明和私有声明
        DefaultClaims defaultClaims = new DefaultClaims();
        defaultClaims.setIssuer(jwtProperties.getPayload().getRegisterdClaims().getIss());
        defaultClaims.setExpiration(new Date(System.currentTimeMillis() + expireTime));
        defaultClaims.setSubject(subject);
        defaultClaims.setAudience(jwtProperties.getPayload().getRegisterdClaims().getAud());

        JwtBuilder builder = Jwts.builder() // 表示new一个JwtBuilder，设置jwt的body
                .setClaims(defaultClaims)
                .setIssuedAt(nowDate) // iat(issuedAt)：jwt的签发时间
                .signWith(SignatureAlgorithm.forName(jwtProperties.getHeader().getAlg()), key); // 设置签名，使用的是签名算法和签名使用的秘钥

        return builder.compact();
    }

    /**
     * 解密jwt
     * @param jwt
     * @return
     * @throws Exception
     */
    public Claims parseJWT(String jwt) throws Exception {
        SecretKey key = generalKey(); // 签名秘钥，和生成的签名的秘钥一模一样
        Claims claims = Jwts.parser() // 得到DefaultJwtParser
                .setSigningKey(key) // 设置签名的秘钥
                .parseClaimsJws(jwt).getBody(); // 设置需要解析的jwt
        return claims;
    }

    public boolean isValidToken(String token) {
        // 此处添加token验证逻辑
        try {
            ThrowUtils.throwIf(token == null, ErrorCode.NOT_LOGIN_ERROR, "token为空");
            Claims claims = this.parseJWT(token);
            String subject = claims.getSubject();
            // 可以正确被解析，说明token正确
            User user = JSONUtil.toBean(subject, User.class);
            ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN_ERROR, "未登录");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true; // 示例中简化为始终返回true
    }

    public String getToken(User user) {
        String userJsonStr = null;
        try {
            userJsonStr = JSONUtil.toJsonStr(user);
            return this.createJWT(userJsonStr);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "生成token失败:" + e.getMessage());
        }
    }
}